package jvProjects.imageFusion;

import gif.GifFrame;
import gif.ImageUtil;
import help.DeformationHanlderTransfare;
import deformation.Deformation;
import deformation.DeformationGenerator.DeformationType;
import deformation.point.AffinePointDeformation;
import deformation.point.RigidPointDeformation;
import deformedGrid.painter.DeformationPainter;
import fusion.LinearCombination;
import fusion.gui.FusionFrame;
import handler.LineHandler;

import java.awt.AWTException;
import java.awt.FileDialog;
import java.awt.GridLayout;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.imageio.ImageIO;

import jv.anim.PsTimeEvent;
import jv.project.PjProject;
import jv.project.PvDisplayIf;
import jv.viewer.PvDisplay;
import jvDeformation.JvDeformationDisplay;
import jvDeformation.JvDeformationHandler;
import jvDeformation.JvGrid;

/**
 * @see jv.anim.PsAnimation
 * @see jv.geom.PgElementSet
 * @see jv.project.PjProject
 */
public class PjFusion extends PjProject {

	/**
	 * 
	 */
	private static final long serialVersionUID = 2417563575142658450L;
	//private JvGrid jgrid;
	JvDeformationHandler defH;

	/**
	 * Constructor, without arguments to allow loading of project from menu.
	 */
	public PjFusion() {
		super("Image Fusion");

		init();
	}

	/**
	 * Do initialization of data structures; method is also used to reset
	 * instances.
	 */
	@Override
	public void init() {
		super.init();
	}
	/**
	 * Start project, e.g. start an animation. Method is called once when
	 * project is selected in PvViewer#selectProject(). Method is optional. For
	 * example, if an applet calls the start() method of PvViewer, then PvViewer
	 * tries to invoke the start() method of the currently selected project.
	 */
	
	JvDeformationDisplay defdis1;
	JvDeformationDisplay defdis2;
	@Override
	public void start() {

		m_display.setEnabled3DLook(false);
		Robot robo = null;
		try {
			robo = new Robot();
		} catch (AWTException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		BufferedImage bi = robo.createScreenCapture(new Rectangle(Toolkit
				.getDefaultToolkit().getScreenSize()));
		PvDisplayIf jvdisplay1 = m_display;
		PvDisplayIf jvdisplay2 = getViewer().newDisplay("display2", false);
		this.addDisplay(jvdisplay2);
		m_display.getCanvas().getParent().setLayout(new GridLayout(1, 0));
		m_display.getCanvas().getParent().add(jvdisplay2.getCanvas());
		defdis1 = new JvDeformationDisplay(jvdisplay1, bi,
				50, 50);
		defdis2 = defdis1.generateSynctDisplay(jvdisplay2);
		// super.start();

	}

	/**
	 * Update method of project to react on changes in its panel or of its
	 * children. This method is optional, but required if project is parent of a
	 * child. Project becomes parent if child calls
	 * <code>child.setParent(this)</code> with this project as argument. For
	 * example, see the constructor of MyProject. Project must react on child
	 * events, or forward them to its superclass.
	 * <p>
	 * Catch events of integer children and recompute surface.
	 */
	@Override
	public boolean update(Object event) {
		if (event == getInfoPanel()) {

			return super.update(this);
		}
		return super.update(event);
	}

	/**
	 * Put your algorithms/methods here in the Pj...-class. They have access to
	 * the active geometry on the display and several other important objects
	 * and can be invoked from the GUI-class Pj..._IP, e.g. on button-click
	 * events. Make sure your method is public or protected so that it can be
	 * accessed by other classes.
	 */

	protected void loadImage1() {
		defdis1.loadnewImage();
		if (fusion != null) {
			fusion.setImage1(defdis1.getJvGrid().image);
		}
		
	}
	
	protected void loadImage2() {
		defdis2.loadnewImage();
		if (fusion != null) {
			fusion.setImage2(defdis2.getJvGrid().image);
		}
	}

	LinearCombination fusion;
	FusionFrame fFrame;
	DeformationHanlderTransfare trans1;
	DeformationHanlderTransfare trans2;
	double factor= 0.5;
	double color_factor = 0.5;
	public void fuse() {
		if (this.fusion == null) {
			fusion = new LinearCombination(defdis1.gridPointsX.get(), defdis2.gridPointsY.get(),
					defdis1.getJvGrid().image,
					defdis2.getJvGrid().image);
			LineHandler pointHandler1 = defdis1
					.getJvDeformationHandler().generateHandler();
			LineHandler pointHandler2 = defdis2
					.getJvDeformationHandler().generateHandler();
			trans1 = new DeformationHanlderTransfare(
					pointHandler1,
					defdis1.getJvGrid().image.getHeight());
			trans2 = new DeformationHanlderTransfare(
					pointHandler2,
					defdis2.getJvGrid().image.getHeight());
			fusion.setDeformations(
					defdis1.generateNewDeformation(trans1.getTransfareLineHandler()),
					defdis2.generateNewDeformation(trans2.getTransfareLineHandler()));
			fFrame = new FusionFrame(fusion);
		}else{
			trans1.destroy();
			trans2.destroy();
			fusion.setNumGridPoints(defdis1.gridPointsX.get(), defdis2.gridPointsY.get());
			fusion.getDeformationPainter1().removeDeformation();
			fusion.getDeformationPainter2().removeDeformation();
			LineHandler pointHandler1 = defdis1
					.getJvDeformationHandler().generateHandler();
			LineHandler pointHandler2 = defdis2
					.getJvDeformationHandler().generateHandler();
			trans1 = new DeformationHanlderTransfare(
					pointHandler1,
					defdis1.getJvGrid().image.getHeight());
			trans2 = new DeformationHanlderTransfare(
					pointHandler2,
					defdis2.getJvGrid().image.getHeight());
			fusion.setDeformations(
					defdis1.generateNewDeformation(trans1.getTransfareLineHandler()),
					defdis2.generateNewDeformation(trans2.getTransfareLineHandler()));
			fFrame.setVisible(true);
			fFrame.resize();
		}
	}

	public void setFusionFactor(double factor, double color_factor) {
		this.factor = factor;
		this.color_factor  = color_factor;
		fFrame.setFactor(factor, color_factor);
		
	}
	
	public void saveImage_gif(){
		if (this.fusion == null) {
			return;
		}
        FileDialog fileDialog = new FileDialog(getViewer().getFrame(), "Save", FileDialog.SAVE);
        fileDialog.setFilenameFilter(new FilenameFilter() {
            public boolean accept(File dir, String name) {
                return name.endsWith(".gif");
            }
        });
        fileDialog.setFile("Untitled.gif");
        fileDialog.setVisible(true);
        if (fileDialog.getFile() != null) {
		try {
			BufferedImage image1 = defdis1.getJvGrid().image;
			BufferedImage image2 = defdis2.getJvGrid().image;
			LinearCombination comp = new LinearCombination(2*defdis1.gridPointsX.get(), 2*defdis2.gridPointsY.get(), image1, image2);
			comp.setDeformations(
					defdis1.generateNewDeformation(trans1.getTransfareLineHandler()),
					defdis2.generateNewDeformation(trans2.getTransfareLineHandler()));
		//BufferedImage bi = fusion.getfuseImage(factor);
		List<GifFrame> gifFrames = new ArrayList<GifFrame>();

		   for(double x = 0; x <= 1.02; x+=0.05)
		   {
			   System.out.println(x);
		      int transparantColor = 0xFF00FF; // purple
		      BufferedImage gif = ImageUtil.convertRGBAToGIF(fusion.getfuseImage(x), transparantColor);
		      long delay = 100; // every frame takes 100ms
		      String disposal = GifFrame.RESTORE_TO_BGCOLOR; // make transparent pixels not 'shine through'
		      gifFrames.add(new GifFrame(gif, delay, disposal));
		   }

		   int loopCount = 0; // loop indefinitely
		  
		File outputfile = new File(fileDialog.getDirectory() + fileDialog.getFile());
		
		ImageUtil.saveAnimatedGIF( new FileOutputStream(outputfile), gifFrames, loopCount);
		
		//ImageIO.write(bi, "gif", outputfile);
	} catch (IOException e) {
		System.out.println("fail");
	} catch (Exception e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}}
	}
	
	
	public void saveImage(){
		if (this.fusion == null) {
			return;
		}
        FileDialog fileDialog = new FileDialog(getViewer().getFrame(), "Save", FileDialog.SAVE);
        fileDialog.setFilenameFilter(new FilenameFilter() {
            public boolean accept(File dir, String name) {
                return name.endsWith(".png");
            }
        });
        fileDialog.setFile("Untitled.png");
        fileDialog.setVisible(true);
        if (fileDialog.getFile() != null) {
		try {
			BufferedImage image1 = defdis1.getJvGrid().image;
			BufferedImage image2 = defdis2.getJvGrid().image;
			LinearCombination comp = new LinearCombination(2*defdis1.gridPointsX.get(), 2*defdis2.gridPointsY.get(), image1, image2);
			comp.setDeformations(
					defdis1.generateNewDeformation(trans1.getTransfareLineHandler()),
					defdis2.generateNewDeformation(trans2.getTransfareLineHandler()));
		BufferedImage bi = fusion.getfuseImage(factor);
		File outputfile = new File(fileDialog.getDirectory() + fileDialog.getFile());
		ImageIO.write(bi, "png", outputfile);
	} catch (IOException e) {
		System.out.println("fail");
	}}
	}

}
